package com.tierstall.server;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Restrictions;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.tierstall.client.service.SessionService;
import com.tierstall.client.service.TierService;
import com.tierstall.server.model.Gruppe;
import com.tierstall.server.model.Tier;
import com.tierstall.server.model.User;
import com.tierstall.shared.GruppeDTO;
import com.tierstall.shared.Logger;
import com.tierstall.shared.SearchQuery;
import com.tierstall.shared.SessionInvalidException;
import com.tierstall.shared.TierDTO;
import com.tierstall.shared.UserDTO;
import com.tierstall.util.HibernateUtil;

@SuppressWarnings("serial")
public class TierServiceImpl extends RemoteServiceServlet implements
		TierService {
	ServiceHelper helper;

	public TierServiceImpl() {
		helper = ServiceHelper.getInstance();
	}

	private HttpSession getSession() {
		HttpServletRequest request = this.getThreadLocalRequest();
		return request.getSession();
	}

	@Override
	public TierDTO addTier(String sessionId, TierDTO tier)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// Method
		if (tier.getUuid() != null && !tier.getUuid().equals("")) {
			Session session = HibernateUtil.getSessionFactory().openSession();
			Transaction transaction = null;
			String tierID = "";
			try {
				transaction = session.beginTransaction();
				tierID = ((UUID) session.save(new Tier(tier))).toString();
				transaction.commit();
				tier.setUuid(tierID.toString());
				Logger.SERVER_INFO("Saved Tier with UUID: " + tierID.toString());
			} catch (HibernateException e) {
				Logger.SERVER_INFO("addTier unsuccessfull!");
				transaction.rollback();
				e.printStackTrace();
			} finally {
				session.close();
			}
			return tier;
		} else
			return null;
	}

	@Override
	public TierDTO updateTier(String sessionId, TierDTO tier)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// Method
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			session.update(new Tier(tier));
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
			return null;
		} finally {
			session.close();
		}
		return tier;
	}

	@Override
	public TierDTO getTier(String sessionId, String id)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// Method
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		TierDTO tier;
		try {
			transaction = session.beginTransaction();
			tier = helper.createTierDTO((Tier) session.load(Tier.class,
					UUID.fromString(id)));
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
			return null;
		} finally {
			session.close();
		}
		return tier;
	}

	@Override
	public Boolean deleteTier(String sessionId, String id)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// Method
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			Tier tier = (Tier) session.load(Tier.class, UUID.fromString(id));
			session.delete(tier);
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
			return false;
		} finally {
			session.close();
		}
		return true;
	}

	@Override
	public ArrayList<TierDTO> getTiere(String sessionId)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// Method
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		ArrayList<TierDTO> tierList = new ArrayList<TierDTO>();
		try {
			transaction = session.beginTransaction();
			List tier = session.createQuery("from Tier").list();
			for (Iterator iterator = tier.iterator(); iterator.hasNext();) {
				tierList.add(helper.createTierDTO((Tier) iterator.next()));
			}
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
			return null;
		} finally {
			session.close();
		}
		return tierList;
	}

	@Override
	public ArrayList<TierDTO> deleteTiere(String sessionId,
			ArrayList<String> ids) throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// method
		for (int i = 0; i < ids.size(); ++i) {
			deleteTier(sessionId, ids.get(i));
		}

		return getTiere(sessionId);
	}

	// Gruppe + Tier

	@Override
	public ArrayList<TierDTO> getTiereByGroup(String sessionId, GruppeDTO group)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// Method
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		ArrayList<TierDTO> tierList = new ArrayList<TierDTO>();
		try {
			transaction = session.beginTransaction();
			List tier = session.createCriteria(Tier.class)
					.add(Restrictions.eq("gruppe.uuid", group.getUuid()))
					.list();
			for (Iterator iterator = tier.iterator(); iterator.hasNext();) {
				tierList.add(helper.createTierDTO((Tier) iterator.next()));
			}
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
			return null;
		} finally {
			session.close();
		}
		return tierList;
	}

	@Override
	public ArrayList<TierDTO> importTiere(String sessionId,
			ArrayList<TierDTO> tiere) throws SessionInvalidException {
		ArrayList<TierDTO> list = new ArrayList<TierDTO>();
		for (int i = 0; i < tiere.size(); ++i) {
			list.add(addTier(sessionId, tiere.get(i)));
		}
		return list;
	}

	// Gruppe

	@Override
	public GruppeDTO addGroup(String sessionId, GruppeDTO group)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// Method
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		String groupID = "";
		try {
			transaction = session.beginTransaction();
			groupID = ((UUID) session.save(new Gruppe(group))).toString();
			transaction.commit();
			group.setUuid(groupID.toString());
			Logger.SERVER_INFO("Saved Group with UUID: " + groupID.toString());
		} catch (HibernateException e) {
			Logger.SERVER_INFO("addGroup unsuccessfull!");
			transaction.rollback();
			e.printStackTrace();
			return null;
		} finally {
			session.close();
		}
		return group;
	}

	@Override
	public GruppeDTO updateGroup(String sessionId, GruppeDTO group)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			session.update(new Gruppe(group));
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
			return null;
		} finally {
			session.close();
		}
		return group;
	}

	@Override
	public GruppeDTO getGroup(String sessionId, String id)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// Method
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		GruppeDTO group;
		try {
			transaction = session.beginTransaction();
			group = this.helper.createGroupDTO((Gruppe) session.load(Gruppe.class,
					UUID.fromString(id)));
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
			return null;
		} finally {
			session.close();
		}
		return group;
	}

	@Override
	public Boolean deleteGroup(String sessionId, String id)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			Gruppe tier = (Gruppe) session.load(Gruppe.class,
					UUID.fromString(id));
			session.delete(tier);
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
			return false;
		} finally {
			session.close();
		}
		return true;
	}

	@Override
	public ArrayList<GruppeDTO> getGroups(String sessionId)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// Method
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		ArrayList<GruppeDTO> groupList = new ArrayList<GruppeDTO>();
		try {
			transaction = session.beginTransaction();
			List group = session.createQuery("from Gruppe").list();

			for (Iterator iterator = group.iterator(); iterator.hasNext();) {
				groupList.add(this.helper.createGroupDTO((Gruppe) iterator.next()));
			}
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
			return null;
		} finally {
			session.close();
		}
		return groupList;
	}

	@Override
	public ArrayList<TierDTO> queryTiere(String sessionId, SearchQuery query)
			throws SessionInvalidException {
		helper.checkSession(getSession(), sessionId);
		// Method
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		ArrayList<TierDTO> tierList = new ArrayList<TierDTO>();
		try {
			transaction = session.beginTransaction();
			Criteria criteria = session
					.createCriteria(Tier.class);
			
			if (query.getGroup() != null){ // Genehmigung
				criteria.createCriteria("group").
				add(Restrictions.eq("uuid", new Gruppe(query.getGroup()).getUuid()));
			}
			
			if (query.getUser() != null){ // user/editor
				criteria.createCriteria("editor").
				add(Restrictions.eq("id", new User(query.getUser()).getId()));
			}
			
			if (query.getOrigin() != null){ // origin
				criteria.add(Restrictions.ilike("origin", "%"+query.getOrigin()+"%"));
			}
			
			if (query.getType() != null){ // tiertype
				criteria.add(Restrictions.eq("type", query.getType()));
			}
			
			if (query.getGender() != null){ // gender
				criteria.add(Restrictions.eq("gender", query.getGender()));
			}
			
			if (query.getStamm() != null){ // stamm
				criteria.add(Restrictions.ilike("stamm", "%"+query.getStamm()+"%"));
			}
		
//			if (query.getAlter() >= 0){ // gender
//				criteria.add(Restrictions.eq("GENDER", query.getAlter()));
//			}
			
			if (query.getStart() != null){
				criteria.add(Restrictions.ge("entry",query.getStart()));
			}
			if (query.getEnd() != null){
				criteria.add(Restrictions.ge("dispatch",query.getEnd()));
			}			
			
			List tier = criteria.list();
			Logger.SERVER_INFO("Query Result: " + tier.size() + " Tiere filtered");
			for (Iterator iterator = tier.iterator(); iterator.hasNext();) {
				tierList.add(helper.createTierDTO((Tier) iterator.next()));
			}
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
			return null;
		} finally {
			session.close();
		}
		return tierList;

	}


}
